package com.hongye.why.base.listenin;

import android.os.Looper;
import android.util.SparseArray;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 监听中心
 */
public class Listenin {
    /**
     * 主线程监听集合
     */
    private final SparseArray<List<Watcher>> mainWatchers = new SparseArray<>();
    /**
     * 当前线程的监听者集合
     */
    private final SparseArray<List<Watcher>> currentWatchers = new SparseArray<>();
    /**
     * 子线程监听集合
     */
    private final SparseArray<List<Watcher>> otherWatchers = new SparseArray<>();
    /**
     * 主线程处理
     */
    private final MessagePosterHandler mainHandler = new MessagePosterHandler(10, Looper.myLooper(),this);
    /**
     * 其他线程
     */
    private final OtherThreadMessagePoster otherHandler = new OtherThreadMessagePoster(this);
    /**
     * 节省型线程池
     */
    ExecutorService executor = Executors.newCachedThreadPool();
    /**
     * 默认渠道
     */
    private static final int DEFAULT_CHANNEL = 0;
    /**
     *
     */
    private static Listenin defaultListenin;

    /**
     *
     * @return
     */
    public static Listenin getDefault() {
        synchronized (Listenin.class) {
            if (defaultListenin == null) {
                defaultListenin = new Listenin();
            }
            return defaultListenin;
        }
    }

    /**
     * 注册主线程上的监听器
     *
     * @param watcher Watcher
     */
    public void registerMainThreadWatcher(Watcher watcher) {
        registerMainThreadWatcher(watcher, DEFAULT_CHANNEL);
    }

    /**
     * 注册主线程上的监听器
     *
     * @param watcher Watcher
     */
    public void registerMainThreadWatcher(Watcher watcher, int channel) {
        synchronized (mainWatchers) {
            List<Watcher> list = mainWatchers.get(channel);
            if (list == null) {
                list = new ArrayList<>();
                mainWatchers.put(channel, list);
            }
            if (!list.contains(watcher)) {
                list.add(watcher);
            }
        }
    }

    /**
     * 注册当前线程的监听器
     *
     * @param watcher Watcher
     */
    public void registerWatcher(Watcher watcher) {
        this.registerWatcher(watcher,DEFAULT_CHANNEL);
    }

    /**
     *
     * @param watcher Watcher
     * @param channel int
     */
    public void registerWatcher(Watcher watcher,int channel) {
        synchronized (currentWatchers) {
            List<Watcher> list = currentWatchers.get(channel);
            if (list == null) {
                list = new ArrayList<>();
                currentWatchers.put(channel, list);
            }
            if (!list.contains(watcher)) {
                list.add(watcher);
            }
        }
    }

    /**
     * 注册在子线程的监听器
     *
     * @param watcher Watcher
     */
    public void registerOtherThreadWatcher(Watcher watcher) {
        registerOtherThreadWatcher(watcher,DEFAULT_CHANNEL);
    }

    /**
     *
     * @param watcher Watcher
     * @param channel int
     */
    public void registerOtherThreadWatcher(Watcher watcher,int channel) {
        synchronized (otherWatchers) {
            List<Watcher> list = otherWatchers.get(channel);
            if (list == null) {
                list = new ArrayList<>();
                otherWatchers.put(channel, list);
            }
            if (!list.contains(watcher)) {
                list.add(watcher);
            }
        }
    }

    /**
     * 取消注册监听
     *
     * @param watcher Watcher
     */
    public void unregisterWatcher(Watcher watcher) {
        synchronized (mainWatchers) {
            for (int i = 0; i < mainWatchers.size(); i++) {
                List<Watcher> watchers = mainWatchers.valueAt(i);
                watchers.remove(watcher);
            }
        }
        synchronized (currentWatchers) {
            for (int i = 0; i < currentWatchers.size(); i++) {
                List<Watcher> watchers = currentWatchers.valueAt(i);
                watchers.remove(watcher);
            }
        }
        synchronized (otherWatchers) {
            for (int i = 0; i < otherWatchers.size(); i++) {
                List<Watcher> watchers = otherWatchers.valueAt(i);
                watchers.remove(watcher);
            }
        }
    }

    /**
     * 发送消息到默认渠道
     *
     * @param message Message
     */
    public void sendMessage(Message message) {
        sendMessage(message, DEFAULT_CHANNEL);
    }

    /**
     * 指定渠道发送消息
     *
     * @param message Message
     * @param channel int
     */
    public void sendMessage(Message message, int channel) {
        List<Watcher> mainWs = mainWatchers.get(channel);
        if (mainWs != null) {
            for (Watcher watcher : mainWs) {
                postToWatcher(watcher, message, 1);
            }
        }
        List<Watcher> currentWs = currentWatchers.get(channel);
        if (currentWs != null) {
            for (Watcher watcher : currentWs) {
                postToWatcher(watcher, message, 2);
            }
        }
        List<Watcher> otherWs = otherWatchers.get(channel);
        if (otherWs != null) {
            for (Watcher watcher : otherWs) {
                postToWatcher(watcher, message, 3);
            }
        }
    }

    /**
     * @param watcher    Watcher
     * @param message    Message
     * @param threadMode int
     */
    private void postToWatcher(Watcher watcher, Message message, int threadMode) {
        MessagePoster poster = MessagePoster.obtainPoster(message, watcher);
        switch (threadMode) {
            case 1:
                mainHandler.enqueue(poster);
                break;
            case 2:
                invokePoster(poster);
                break;
            case 3:
                otherHandler.enqueue(poster);
                break;
        }
    }

    /**
     * @param poster MessagePoster
     */
    protected void invokePoster(MessagePoster poster) {
        Watcher watcher = poster.watcher;
        Message message = poster.message;
        if (watcher != null) {
            watcher.receiveMessage(message);
        }
        MessagePoster.releaseMessagePoster(poster);
    }

}
